/*
 * Copyright (C) 2009 Show SMS open source project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bydavy.android.showsms;

//~--- non-JDK imports --------------------------------------------------------

import android.app.Service;

import android.content.Intent;

import android.database.ContentObserver;
import android.database.Cursor;

import android.net.Uri;

import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;

import android.util.Log;

import com.bydavy.android.showsms.model.SimpleMessage;
import com.bydavy.android.showsms.model.SimpleMessageFactory;
import com.bydavy.android.showsms.ui.PreviewActivity;
import com.bydavy.android.showsms.util.AppLog;

/**
 * This class will queued all intent received by his starting call.
 * Intent queued will by transform in message an send intents.
 *
 * @version        1.0, 09/06/21
 * @author         Davy L.
 */
public class MsgReceiverService extends Service {
    //~--- static fields ------------------------------------------------------

    private static final String LOG_TAG = AppLog.LOG_TAG;
    private static final boolean DEBUG  = false;

    //~--- fields -------------------------------------------------------------

    /** Handler for the mThread */
    private MessageHandler mHandler;

    /** Loop of the mThread */
    private Looper mServiceLooper;

    /** thread that manage SMS received */
    private HandlerThread mThread;

    //~--- methods ------------------------------------------------------------

    /**
     * Create the thread, Handler and load preferences (enabled status)
     *
     */
    @Override
    public void onCreate() {
        super.onCreate();

        if (DEBUG) {
            Log.v(LOG_TAG, "MsgReceiverService : onCreate");
        }

        // Create the SMS manager thread
        mThread = new HandlerThread("Show SMS HandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
        mThread.start();
        mServiceLooper = mThread.getLooper();
        mHandler       = new MessageHandler(mServiceLooper);
    }

    /**
     * Called on Service destruction
     *
     */
    @Override
    public void onDestroy() {
        super.onDestroy();

        if (DEBUG) {
            Log.v(LOG_TAG, "MsgReceiverService : Destroy");
        }

        mServiceLooper.quit();
    }

    /**
     * Called when the activity try to bind
     *
     * @param arg0
     * @return
     */
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    /**
     * Put the intent in the thread queue
     *
     * @param intent intent to post in the thread queue
     * @param startId service Id killed after message queued processed
     */
    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);

        if (DEBUG) {
            Log.v(LOG_TAG, "MsgReceiverService :onStart()");
        }

        // Notify the User quickly
        notifyWhenDBUpdated();
        mHandler.processMessage(intent, startId);
    }

    /**
     * Notify the user when the new message was stored in the database
     * (Stored by the genuine android message application)
     */
    private void notifyWhenDBUpdated() {

        // New thread create (processing is time consuming)
        new Thread(new Runnable() {
            private Handler coHandler;
            @Override
            public void run() {
                String[] selection  = new String[] { "_id" };
                final Cursor cursor = getContentResolver().query(Uri.parse("content://sms/inbox"), selection, null,
                                          null, null);
                ContentObserver co = new ContentObserver(coHandler) {
                    @Override
                    public void onChange(boolean selfChange) {
                        super.onChange(selfChange);

                        if (DEBUG) {
                            Log.d(LOG_TAG, "ShortMessage DataBase updated");
                        }

                        cursor.unregisterContentObserver(this);
                        MessageNotification.updateNotifications(getApplicationContext());
                    }
                };

                cursor.registerContentObserver(co);
            }
        }).start();
    }

    //~--- inner classes ------------------------------------------------------

    /**
     * Handler that will process all intent queued
     *
     */
    private final class MessageHandler extends Handler {

        /** Type of message send to the handler queue */
        private static final int MSG_TO_PROCESS = 1;

        public MessageHandler(Looper looper) {
            super(looper);
        }

        /**
         * To send a message to the handler
         *
         * @param intent intent containing the message to process
         * @param serviceId
         */
        public void processMessage(Intent intent, int serviceId) {
            Message msg = new Message();

            msg.what = MSG_TO_PROCESS;
            msg.arg1 = serviceId;
            msg.obj  = intent.getExtras();
            mHandler.sendMessage(msg);
        }

        /**
         * Transform the intent contains by the message to a MESSAGE and send intent
         *
         *
         * @param msg message to process
         */
        @Override
        public void handleMessage(Message msg) {
            if (DEBUG) {
                Log.v(LOG_TAG, "MessageHandler : handleMessage()");
            }

            // Unique type of message for the moment
            if (msg.what == MSG_TO_PROCESS) {

                int serviceId = msg.arg1;
                Bundle bundle = (Bundle) msg.obj;

                try {
                    SimpleMessage message = SimpleMessageFactory.extract(bundle, getApplicationContext());
                    Intent intent         = new Intent();

                    Log.d(LOG_TAG, "Message send to activity:" + message);
                    intent.putExtras(message.toBundle());
                    intent.setClass(getApplicationContext(), PreviewActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);

                    startActivity(intent);
                } catch (Exception e) {
                    Log.e(LOG_TAG, "Message can't be extracted from PDU");
                }

                // Test if there are new messages on queue
                if (this.hasMessages(MSG_TO_PROCESS)) {
                    if (DEBUG) {
                        Log.v(LOG_TAG, "Other messages");
                    }
                } else {
                    if (DEBUG) {
                        Log.v(LOG_TAG, "No other messages");
                    }

                    // kill the MsgReceiverService
                    stopSelf(serviceId);
                }
            }
        }
    }
}
